#include "cbb_queue.h"
#include <stdint.h>
#include <string.h>

// 队列状态
enum {
    QUEUE_IDLE,
    QUEUE_BUSY,
};

Queue_t*
cbb_queue_register(uint16_t u16ObjSize, uint16_t u16MaxCnt){

    // 申请队列句柄内存
    Queue_t* pQueue = (Queue_t*)QUEUE_MALLOC(sizeof(Queue_t));
    if(NULL == pQueue) return NULL;

    // 申请队列缓存
    uint8_t* pu8Cache = (uint8_t*)QUEUE_MALLOC(u16ObjSize * u16MaxCnt);
    if(NULL == pu8Cache) return NULL;

    // 初始化队列
    memset(pu8Cache, 0, u16ObjSize * u16MaxCnt);
    pQueue->pu8Cache = pu8Cache;
    pQueue->u16ObjSize = u16ObjSize;
    pQueue->u16Cnt = 0;
    pQueue->u16MaxCnt = u16MaxCnt;
    pQueue->u16Head = 0;
    pQueue->u16Tail = 0;

    // 返回队列句柄
    return pQueue;
}
 
QUEUE_RET_t
queue_psuh(Queue_t* pstQueue, void* pvObj){

    // 输入参数判断
    if(NULL == pstQueue || NULL == pvObj) return QUEUE_RET_ERR;

    // 队列已满
    if(pstQueue->u16Cnt >= pstQueue->u16MaxCnt) return QUEUE_RET_FULL;

    // 队列空闲判断
    if(QUEUE_BUSY == pstQueue->u16Flag) return QUEUE_RET_BUSY;

    // 锁定队列 -- 防止多线程干扰
    pstQueue->u16Flag = QUEUE_BUSY;

    // 计算缓存区偏移
    uint16_t u16Offset = pstQueue->u16Head * pstQueue->u16ObjSize;

    // 复制对象到缓存区
    memcpy(pstQueue->pu8Cache + u16Offset, (uint8_t*)pvObj, pstQueue->u16ObjSize);

    // 队列计数+1
    pstQueue->u16Cnt++;

    // 计算队列头指针
    pstQueue->u16Head = (pstQueue->u16Head + 1) % pstQueue->u16MaxCnt;

    // 解锁队列
    pstQueue->u16Flag = QUEUE_IDLE;

    // 返回成功
    return QUEUE_RET_OK;
}

QUEUE_RET_t
cbb_queue_pull(Queue_t* pstQueue, void* pvObj){

    // 输入参数判断
    if(NULL == pstQueue || NULL == pvObj) return QUEUE_RET_ERR;

    // 队列空判断
    if(0 == pstQueue->u16Cnt) return QUEUE_RET_EMPTY;

    // 队列空闲判断
    if(QUEUE_BUSY == pstQueue->u16Flag) return QUEUE_RET_BUSY;

    // 锁定队列 -- 防止多线程干扰
    pstQueue->u16Flag = QUEUE_BUSY;

    // 计算缓存区偏移
    uint16_t u16Offset = pstQueue->u16Tail * pstQueue->u16ObjSize;

    // 复制对象到缓存区
    memcpy((uint8_t*)pvObj, pstQueue->pu8Cache + u16Offset, pstQueue->u16ObjSize);
    
    // 清空缓存区
    memset(pstQueue->pu8Cache + u16Offset, 0, pstQueue->u16ObjSize);
    
    // 队列计数+1
    pstQueue->u16Cnt--;

    // j计算队列尾指针
    pstQueue->u16Tail = (pstQueue->u16Tail + 1) % pstQueue->u16MaxCnt;

    // 解锁队列
    pstQueue->u16Flag = QUEUE_IDLE;

    // 返回成功
    return QUEUE_RET_OK;
}
